//
// Created by 乐亦聪 on 12/28/15.
//

#include <getopt.h>
#include <stdlib.h>

#include "lwan.h"
#include "lwan-serve-files.h"

enum args {
    ARGS_FAILED,
    ARGS_USE_CONFIG,
    ARGS_SERVE_FILES
};

lwan_http_status_t
hello_world(lwan_request_t *request,
            lwan_response_t *response,
            void *data __attribute__((unused)))
{
    static lwan_key_value_t headers[] = {
            { NULL, NULL }
    };
    response->headers = headers;
    response->mime_type = "text/plain";

    strbuf_printf(response->buffer, "OK");

    return HTTP_OK;
}

lwan_http_status_t
list_ad(lwan_request_t *request,
        lwan_response_t *response,
        void *data __attribute__((unused)))
{
    static lwan_key_value_t headers[] = {
            { .key = "X-The-Answer-To-The-Universal-Question", .value = "42" },
            { NULL, NULL }
    };
    response->headers = headers;
    response->mime_type = "text/plain";

    redisReply * reply;

    char buf[10240];
    char buf2[1024];
    char buf3[1024];
    char buf4[10240];

    const char* endUserSn = lwan_request_get_query_param(request, "endUserSn");
    const char* triggerType = lwan_request_get_query_param(request, "triggerType");
    const char* appToken = lwan_request_get_query_param(request, "appToken");
    const char* jsonBeacons = lwan_request_get_query_param(request, "jsonBeacons");

    if (jsonBeacons == nullptr) {
        return HTTP_OK;
    }

    raipdjson::Document d;
    d.Parse(jsonBeacons);

    const char *name = lwan_request_get_query_param(request, "name");
    if (name)
        strbuf_printf(response->buffer, "Hello, %s!", name);
    else
        strbuf_set_static(response->buffer, "Hello, world!", sizeof("Hello, world!") -1);

    const char *dump_vars = lwan_request_get_query_param(request, "dump_vars");
    if (!dump_vars)
        goto end;

    if (request->cookies.base) {
        strbuf_append_str(response->buffer, "\n\nCookies\n", 0);
        strbuf_append_str(response->buffer, "-------\n\n", 0);

        lwan_key_value_t *qs = request->cookies.base;
        for (; qs->key; qs++)
            strbuf_append_printf(response->buffer,
                                 "Key = \"%s\"; Value = \"%s\"\n", qs->key, qs->value);
    }

    strbuf_append_str(response->buffer, "\n\nQuery String Variables\n", 0);
    strbuf_append_str(response->buffer, "----------------------\n\n", 0);

    lwan_key_value_t *qs = request->query_params.base;
    for (; qs->key; qs++)
        strbuf_append_printf(response->buffer,
                             "Key = \"%s\"; Value = \"%s\"\n", qs->key, qs->value);

    if (!(request->flags & REQUEST_METHOD_POST))
        goto end;

    strbuf_append_str(response->buffer, "\n\nPOST data\n", 0);
    strbuf_append_str(response->buffer, "---------\n\n", 0);

    for (qs = request->post_data.base; qs->key; qs++)
        strbuf_append_printf(response->buffer,
                             "Key = \"%s\"; Value = \"%s\"\n", qs->key, qs->value);

    end:
    return HTTP_OK;
}

static enum args
parse_args(int argc, char *argv[], lwan_config_t *config, char **root)
{
    static const struct option opts[] = {
            { .name = "root", .has_arg = 1, .val = 'r' },
            { .name = "listen", .has_arg = 1, .val = 'l' },
            { .name = "help", .val = 'h' },
            { }
    };
    int c, optidx = 0;
    enum args result = ARGS_USE_CONFIG;

    while ((c = getopt_long(argc, argv, "hr:l:", opts, &optidx)) != -1) {
        switch (c) {
            case 'l':
                free(config->listener);
                config->listener = strdup(optarg);
                result = ARGS_SERVE_FILES;
                break;

            case 'r':
                free(*root);
                *root = strdup(optarg);
                result = ARGS_SERVE_FILES;
                break;

            default:
                printf("Run %s --help for usage information.\n", argv[0]);
                return ARGS_FAILED;

            case 'h':
                printf("Usage: %s [--root /path/to/root/dir] [--listener addr:port]\n", argv[0]);
                printf("\t[--config]\n");
                printf("Serve files through HTTP.\n\n");
                printf("Defaults to listening on all interfaces, port 8080, serving current directory.\n\n");
                printf("Options:\n");
                printf("\t-r, --root      Path to serve files from (default: current dir).\n");
                printf("\t-l, --listener  Listener (default: %s).\n", config->listener);
                printf("\t-h, --help      This.\n");
                printf("\n");
                printf("Examples:\n");
                printf("  Serve system-wide documentation: %s -r /usr/share/doc\n", argv[0]);
                printf("        Serve on a different port: %s -l '*:1337'\n", argv[0]);
                printf("\n");
                printf("Report bugs at <https://github.com/lpereira/lwan>.\n");
                return ARGS_FAILED;
        }
    }

    return result;
}

int
main(int argc, char *argv[])
{
    lwan_t l;
    lwan_config_t c;
    char *root = get_current_dir_name();
    int exit_status = EXIT_SUCCESS;

    c = *lwan_get_default_config();
    c.listener = strdup("*:8080");

    switch (parse_args(argc, argv, &c, &root)) {
        case ARGS_SERVE_FILES:
            lwan_status_info("Serving files from %s", root);
            lwan_init_with_config(&l, &c);

            const lwan_url_map_t map[] = {
                    { .prefix = "/", SERVE_FILES(root) },
                    { }
            };
            lwan_set_url_map(&l, map);
            break;
        case ARGS_USE_CONFIG:
            lwan_init(&l);
            break;
        case ARGS_FAILED:
            exit_status = EXIT_FAILURE;
            goto out;
    }

    lwan_main_loop(&l);
    lwan_shutdown(&l);

    out:
    free(root);

    return exit_status;
}
